#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "imagem.h"
/*+-------------------------------------------------------------------------+
  | Modulo IMAGEM                                               	    |
  | ---------------------                                                   |
  |                                                                         |
  | IMAGEM.C                                                                |
  |                                                                         |
  |            Arquivo que contem as rotinas para ler/gravar imagens em for-|
  | mato PGM ASCII que nada mais e do que formato texto simples de imagens  |
  | em niveis de cinza.					                    |
  +-------------------------------------------------------------------------+*/

/*+-------------------------------------------------------------------------+
  | Rotinas para ALOCAR e DESALOCAR dinamicamente espaco de memoria para um |
  | vetor monodimensional que armazenara a imagem.                         |
  | PARAMETROS:                                                             |
  | nlins = Numero de linhas.                                               |
  | ncols = Numero de colunas.            				    |
  |  Retorna imagem criada			                            |
  +-------------------------------------------------------------------------+*/

Imagem* cria_imagem (int ncols, int nlins) {

  Imagem *img=NULL;
  int i;

  img = (Imagem *) calloc(1,sizeof(Imagem));
  img->val = (int *) calloc(nlins*ncols,sizeof(int));
  img->lin = (int *) calloc(nlins,sizeof(int));

  img->lin[0]=0;
  for (i=1; i < nlins; i++)
    img->lin[i]=img->lin[i-1]+ncols;
  img->ncols = ncols;
  img->nlins = nlins;
 
  return(img);
}

void destroi_imagem (Imagem **img){

  Imagem *aux;
  aux = *img;
  if(aux != NULL){
    if (aux->val != NULL) free(aux->val); 
    if (aux->lin != NULL) free(aux->lin);
    free(aux);    
    *img = NULL;
  }
}


/*+-------------------------------------------------------------------------+
  | Rotina que faz a leitura de uma imagem em formato .PGM ASCII ou binario.|
  | Um exemplo de imagem .PGM ASCII gravada neste formato:                  |
  |                                                                         |
  | P2                                                                      |
  | # CREATOR: XV Version 3.10a  Rev: 12/29/94                              |
  | 124 122                                                                 |
  | 255                                                                     |
  | 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255     |
  | 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255     |
  | (...)                                                                   |
  |                                                                         |
  | Lin 1: contem P2, o que identifica este arquivo como PGM ASCII.         |
  | Lin 2: contem um comentario qualquer iniciado com #.                    |
  | Lin 3: numero de colunas e numero de linhas da imagem.                  |
  | Lin 4: maximo nivel de cinza na imagem (255 normalmente).               |
  | Lin 5: em diante: valores de cinza da imagem.                           |
  |                                                                         |
  | PARAMETROS:                                                             |
  | nome = nome do arquivo de entrada.  	                            |
  |  Retorna imagem lida.			                            |
  +-------------------------------------------------------------------------+*/

Imagem* le_imagem (char *nome) {
  int i, n, k, nlins, ncols, max_nivel;
  char LINHA[100], formato[10];
  unsigned char *valor=NULL;
  FILE *arq;
  Imagem *img;

  if ((arq = fopen (nome, "r")) == NULL) {
     printf ("Erro na ABERTURA do arquivo <%s>\n\n", nome);
     return NULL;
  }
  /*-- PGM = "P2" - ASCII, "P5" - binario -----------*/  
  fgets(formato, 80, arq);
  if (!strstr (formato, "P2") && !strstr (formato, "P5")) {
     printf ("Erro no FORMATO do arquivo <%s>\n\n", nome);  
     return NULL;  
  }
  /*-- Dimensoes da imagem --*/
  do {
     fgets(LINHA, 80, arq);
  } while (strchr (LINHA, '#'));
  sscanf (LINHA, "%d %d", &ncols, &nlins);
  fscanf(arq,"%d",&max_nivel);

  if (nlins == 0 || ncols == 0 || max_nivel == 0) {
     printf ("Erro nas DIMENSOES do arquivo <%s>\n\n", nome);
     return NULL;  
  }

  img = cria_imagem (ncols, nlins);
  n = ncols*nlins;

  if (img != NULL) {   
      if(strstr (formato, "P2")){  
        for (i = 0; i < n; i++) {
	    fscanf (arq, "%d", &k);
            if (k > max_nivel || k < 0) {
               printf ("Erro nos DADOS do arquivo <%s>\n", nome);
	       printf ("Valor lido: %d   Max Nivel: %d\n\n", k, max_nivel);
               return NULL;  
            }	      	      
	    img->val[i]=k; 
        }
      }
      else{
 	valor = (unsigned char *)calloc(n,sizeof(unsigned char));
    	if (valor != NULL){
      	  fread(valor,sizeof(unsigned char),n,arq);
    	}else{
      	   printf ("Erro na ALOCACAO DE MEMORIA para o arquivo <%s>\n", nome);
           destroi_imagem(&img);
           return NULL;
    	}
    	for (i=0; i < n; i++)
      	   img->val[i]=(int)valor[i];
    	free(valor);
      }
  }
  else {
     printf ("Erro na ALOCACAO DE MEMORIA para o arquivo <%s>\n\n", nome);  
     printf ("Rotina: le_imagem_pgm\n\n");
     return NULL;
  }

  fclose (arq);
  return img;
}

/*+-------------------------------------------------------------------------+
  | Rotina que grava o arquivo da imagem em formato PGM ASCII.              |
  | PARAMETROS:                                                             |
  | I    = ponteiro para imagem (entra).                           	    |
  | nome = nome do arquivo (entra).                                         |
  +-------------------------------------------------------------------------+*/

void grava_imagem(Imagem *img, char *nome){

  FILE *arq;
  if ((arq = fopen (nome, "wt")) == NULL) {
      printf ("Erro na CRIACAO do arquivo <%s>\n\n", nome);
  }
  else {
       imprime_imagem(img, arq);
    }
  fclose (arq);
}

void imprime_imagem(Imagem *img, FILE *arq){
 
 int i, n, k, val_por_linha;
 if(arq!=NULL){
   fputs ("P2\n", arq);
   fprintf (arq, "%d  %d\n", img->ncols, img->nlins);
   fprintf (arq, "%d\n", max_val(img));
   val_por_linha = 16;
   n = img->ncols*img->nlins;
   for (i=0, k=0; i < n; i++){    
     fprintf (arq, "%3d ", img->val[i]);
     k++;
     if (k > val_por_linha) {
        fprintf (arq, "\n");
        k = 0;
     }
   }
 }
 else printf ("Erro na GRAVACAO de arquivo\n");
}

/*retorna menor*/ 
int min_val(Imagem *img)
{
  int i,min,n;

  n = img->ncols*img->nlins;
  min = img->val[0];
  for (i=1; i < n; i++)
    if (img->val[i] < min)
      min = img->val[i];

  return(min);
}

/*retorna maior valor de imagem*/ 
int max_val(Imagem *img)
{
  int i,max,n;

  n = img->ncols*img->nlins;
  max = img->val[0];
  for (i=1; i < n; i++)
    if (img->val[i] > max)
      max = img->val[i];

  return(max);
}

/*verifica se pixel esta nos limites da imagem*/
int pixel_valido(Imagem *img, int col, int lin)
{
  if ((col >= 0)&&(col < img->ncols)&&
      (lin >= 0)&&(lin < img->nlins))
    return(1);
  else
    return(0);
}

